package com.asp.aspchain.admin.rest;

import com.alibaba.fastjson.JSON;
import com.asp.aspchain.admin.biz.MgrContractBiz;
import com.asp.aspchain.admin.biz.SequenceBiz;
import com.asp.aspchain.admin.entity.MgrContract;
import com.asp.aspchain.admin.ethereum.EthService;
import com.asp.aspchain.admin.ethereum.PathUtil;
import com.asp.aspchain.admin.request.LoadReq;
import com.asp.aspchain.common.msg.ObjectRestResponse;
import com.asp.aspchain.common.rest.BaseController;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.web3j.crypto.Credentials;
import org.web3j.crypto.WalletUtils;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.RemoteCall;
import org.web3j.tx.gas.ContractGasProvider;
import org.web3j.tx.gas.StaticGasProvider;

import java.lang.reflect.Method;
import java.math.BigInteger;
import java.util.Date;


/**
 * 控制器
 *
 * @author asp
 * @Date 2018-12-17 19:08
 */
@RestController
@RequestMapping("/contract")
public class MgrContractController extends BaseController<MgrContractBiz, MgrContract> {

	private static final Logger logger = LoggerFactory.getLogger(MgrContractController.class);

	@Autowired
	private MgrContractBiz mgrContractBiz;
	@Autowired
	private SequenceBiz sequenceBiz;
	@Autowired
	private EthService ethService;
	@Value("${contract.packagepath}")
	private String packagepath;
	@Value("${contract.keystorepath}")
	private String keystorepath;

	@PostMapping("/deploy")
	public ObjectRestResponse deploy(@RequestBody String json) throws Exception {
		logger.info(json);
		LoadReq loadReq = JSON.parseObject(json, LoadReq.class);

		//设置个人凭证和默认部署需要的gas
		PathUtil pathUtil = new PathUtil(keystorepath);
		pathUtil.addPath(loadReq.getCredentialspath());
		String credentialsPath = pathUtil.toString();
		Credentials credentials = WalletUtils.loadCredentials("", credentialsPath);
		BigInteger GAS_PRICE = BigInteger.valueOf(22_000_000_000L);
		BigInteger GAS_LIMIT = BigInteger.valueOf(4_300_000);
		StaticGasProvider STATIC_GAS_PROVIDER = new StaticGasProvider(GAS_PRICE, GAS_LIMIT);
		//通过映射方式执行部署方法
		Class<?> aClass = null;
		aClass = Class.forName(packagepath + "." + loadReq.getClassname());
		Method deploy = null;
		Integer flag = null;
		try {
			deploy = aClass.getMethod("deploy", new Class[]{Web3j.class, Credentials.class, ContractGasProvider.class, String.class, String.class});
			flag = 1;
		} catch (Exception e) {
			try {
				deploy = aClass.getMethod("deploy", new Class[]{Web3j.class, Credentials.class, ContractGasProvider.class, BigInteger.class, String.class, BigInteger.class, String.class});
				flag = 2;
			} catch (Exception ex) {
				logger.info("有新的部署智能合约方法，请更新代码");
			}
		}
		RemoteCall call = null;
		switch (flag) {
			case 1:
				call = (RemoteCall) deploy.invoke(null, new Object[]{ethService.initWeb3j(), credentials, STATIC_GAS_PROVIDER, loadReq.getTokentype(), loadReq.getTokentype()});
				break;
			case 2:
				call = (RemoteCall) deploy.invoke(null, new Object[]{ethService.initWeb3j(), credentials, STATIC_GAS_PROVIDER, loadReq.getInitsupply(), loadReq.getTokentype(), BigInteger.valueOf(loadReq.getDecimalnum()), loadReq.getTokentype()});
				break;
		}
		Object contractObject = call.send();
		//验证合约是否有效
		Method isValid = aClass.getMethod("isValid", null);
		boolean valid = (boolean) isValid.invoke(contractObject);
		logger.info("合约有效性：" + valid);
		ObjectRestResponse<Object> response = new ObjectRestResponse<>();
		if (!valid) {
			//无效则不执行以下操作
			response.setRel(false);
			return response;
		}
		//获取合约地址
		Method getAddress = aClass.getMethod("getContractAddress", null);
		String address = (String) getAddress.invoke(contractObject);
		logger.info("合约地址：" + address);
		//插入数据
		MgrContract mgrContract = new MgrContract();
		mgrContract.setCid(Integer.parseInt(sequenceBiz.getNextStringValue("cid")));
		mgrContract.setCreatetime(new Date());
		mgrContract.setUpdatetime(mgrContract.getCreatetime());
		mgrContract.setContracttitle(loadReq.getContracttitle());
		mgrContract.setDescriptor(loadReq.getDescriptor());
		mgrContract.setInitsupply(loadReq.getInitsupply());
		mgrContract.setTokentype(loadReq.getTokentype());
		mgrContract.setDecimalnum(loadReq.getDecimalnum());
		mgrContract.setOperator(loadReq.getOperator());
		mgrContract.setOperatortime(new Date());
		mgrContract.setStatus("01");
		mgrContract.setClassname(loadReq.getClassname());
		mgrContract.setCredentialspath(loadReq.getCredentialspath());
		mgrContract.setContractid(address);
		mgrContractBiz.insertSelective(mgrContract);
		response.setRel(true);
		return response;
	}

	public static void main(String[] args) throws Exception {
		/*Class<?> aClass = null;
		aClass = Class.forName("com.asp.aspchain.admin.contract.ERC721Full_sol_ERC721Full");
		Method deploy = aClass.getMethod("deploy", new Class[]{Web3j.class, Credentials.class, ContractGasProvider.class, String.class, String.class});

		Credentials credentials = WalletUtils.loadCredentials("", "C:\\Users\\Administrator\\Desktop\\keystore\\UTC--2018-11-09T03-17-03.599782568Z--5bc3081ca939f8646b2fab357564b94d6f791008");
		BigInteger GAS_PRICE = BigInteger.valueOf(22_000_000_000L);
		BigInteger GAS_LIMIT = BigInteger.valueOf(4_300_000);
		StaticGasProvider STATIC_GAS_PROVIDER = new StaticGasProvider(GAS_PRICE, GAS_LIMIT);

		RemoteCall result = (RemoteCall) deploy.invoke(null, new Object[]{EthServicetest.initWeb3j(), credentials, STATIC_GAS_PROVIDER, "dmt", "dmt"});
		Object send = result.send();
		Method isValid = aClass.getMethod("isValid", null);
		boolean a = (boolean) isValid.invoke(send);
		Method getAddress = aClass.getMethod("getContractAddress", null);
		String address = (String) getAddress.invoke(send);
		System.out.println(address);*/
	}
}